using System;
using FluentTests.Framework.Verbs;

namespace FluentTests.Framework.VerbExtensions
{
    public class VerbAssert<T>
    {
        private readonly Verb<T> verb;
        private readonly Func<T, bool> shouldAssertFunction;

        public VerbAssert(Verb<T> verb, Func<T, bool> shouldAssertFunction)
        {
            this.verb = verb;
            this.shouldAssertFunction = shouldAssertFunction;
        }

        public static void Assert<T>(Verb<T> verb, Func<T, bool> shouldAssertFunc,
                                     string message)
        {
            Assert(verb,shouldAssertFunc,message,new string[]{});
        }

        public static void Assert<T>(Verb<T> verb, Func<T, bool> shouldAssertFunc,
                                     string message, params object[] messageParams)
        {
            
            var negatedMessage = string.Empty;
            if (message.Contains("{not}"))
            {
                negatedMessage = message.Replace("{not}", "");
                if (messageParams.Length > 0)
                    negatedMessage = string.Format(negatedMessage, messageParams);
                message = message.Replace("{not}", "not");
            }
            if (messageParams.Length > 0)
                message = string.Format(message, messageParams);
            
            Assert(verb, shouldAssertFunc, message, negatedMessage);
        }

        public static void Assert<TVerbType>(Verb<TVerbType> verb, Func<TVerbType, bool> shouldAssertFunc, string message,
                                     string negatedMessage)
        {
            var verbAssert = new VerbAssert<TVerbType>(verb, shouldAssertFunc);
            var shouldAssert = verbAssert.ShouldAssert();            
            if (shouldAssert)
                verb.EnsuredWrapperObject.AssertionProvider.Fail(verb.Negated && negatedMessage!=String.Empty ? negatedMessage : message);
        }

        public bool ShouldAssert()
        {        
            bool shouldAssert = shouldAssertFunction(verb.EnsuredWrapperObject.ActualValue);
            if (verb.Negated)
                shouldAssert = !shouldAssert;
            return shouldAssert;
        }


        
    }
}